#include"elf32.h"
#include"string.h"
#include"memory.h"
#include"debug.h"
#include"file.h"
#include"stdio_kernal.h"


//load elf segment to memory
static bool load_segment(int32_t fd,struct Elf32_Phdr* seg){
	uint32_t page_cnt;
	uint32_t va_4k_align;
	uint32_t va;
	uint32_t p_idx=0;
	uint32_t* pde;
	uint32_t* pte;
	
	page_cnt=div_round_up(seg->p_memsz,PG_SIZE);
	va_4k_align=seg->p_vaddr & 0xfffff000;	
	
	while(p_idx<page_cnt){
		va=va_4k_align+PG_SIZE*p_idx;
		pde=pde_ptr(va);
		pte=pte_ptr(va);
		if(!(*pde & 0x1) || !(*pte & 0x01)){
			if(!get_fix_vpage(PG_U,va)){
				return false;
			}
		}
		p_idx++;
	}

	if(sys_lseek(fd,seg->p_offset,SEEK_SET)<0){
		return false;
	}

	if(sys_read(fd,(void*)seg->p_vaddr,seg->p_memsz)<0){
		return false;
	}

	return true;
}

static bool elf_header_check(struct Elf32_Ehdr* eh){

	if(memcmp(eh->e_ident,E_IDENT,7)){
		return false;
	}
	
	if(eh->e_type!=ET_EXEC){
		return false;
	}

	if(eh->e_machine!=EM_386){
		return false;
	}

	if(eh->e_version!=1){
		return false;
	}

	if(eh->e_phentsize!=sizeof(struct Elf32_Phdr)){
		return false;
	}

	return true;
}

//load execute elf in memory return the start entry
uint32_t load_elf32_exec(const char* path){
	struct Elf32_Ehdr elf_header;
	struct Elf32_Phdr phdrs;
	int32_t fd;
	int32_t ret=0;

	if((fd=sys_open(path,O_RDONLY))<0){
		return 0;
	}

	if(sys_read(fd,&elf_header,sizeof(struct Elf32_Ehdr))<0){
		return 0;
	}
	
	if(!elf_header_check(&elf_header)){
		return 0;
	}
	
	int h_idx=0;
	while(h_idx<elf_header.e_phnum){
		//make sure the fd_pos is point to right file offset
		sys_lseek(fd,elf_header.e_phoff+h_idx*elf_header.e_phentsize,SEEK_SET);
		sys_read(fd,&phdrs,sizeof(struct Elf32_Phdr));
		//we only load loadable segment to memory
		if(phdrs.p_type==PT_LOAD){
			//load segment will change fd_pos!!
			if(!load_segment(fd,&phdrs)){
				goto done;
			}
		}
		h_idx++;
	}
	ret=elf_header.e_entry;
done:
	sys_close(fd);
	return ret;
}
